package cn.android666.audiorecorder

import android.Manifest
import android.content.pm.PackageManager
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import androidx.core.app.ActivityCompat
import cn.android666.audiorecorder.aac.AACEncodeThread
import cn.android666.audiorecorder.objectpool.ByteBufferPool
import cn.android666.audiorecorder.pcm.PCMProcessThread
import cn.android666.audiorecorder.pcm.PCMSaveThread
import timber.log.Timber
import java.nio.ByteBuffer
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.thread

object AudioRecorder {

    private const val audioSource = MediaRecorder.AudioSource.MIC
//    private const val sampleRateInHz = 8000
    private const val sampleRateInHz = 44100
    private const val channelConfig = AudioFormat.CHANNEL_IN_MONO
    private const val audioFormat = AudioFormat.ENCODING_PCM_16BIT
    private val minBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
    private val needRun = AtomicBoolean(false)
    private val needSavePCM = false
    private val needSaveAAC = true

    fun startRecord() {
        if (needRun.get()) return
        if (ActivityCompat.checkSelfPermission(App.app, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) return
        val audioRecord = AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, minBufferSize)
        if (audioRecord.state != AudioRecord.STATE_INITIALIZED) {
            Timber.w("录音失败：初始化AudioRecord失败")
            return
        }
        thread { startRecord(audioRecord) }
    }

    private fun startRecord(audioRecord: AudioRecord) {
        Timber.i("开始录音")
        needRun.set(true)
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO)
        audioRecord.startRecording()
        val channelCount = if (channelConfig == AudioFormat.CHANNEL_IN_MONO) 1 else 2
        val pcmProcessThreads = mutableListOf<PCMProcessThread>()
        if (needSavePCM) {
            val pcmSaveThread = PCMSaveThread(ByteBufferPool(minBufferSize, "pcmSaveThread")).also { it.start() }
            pcmProcessThreads.add(pcmSaveThread)
        }
        if (needSaveAAC) {
            val aacEncodeThread = AACEncodeThread(sampleRateInHz, channelCount, minBufferSize, ByteBufferPool(minBufferSize, "aacEncodeThread")).also { it.start() }
            pcmProcessThreads.add(aacEncodeThread)
        }
        val byteBuffer = ByteBuffer.allocateDirect(minBufferSize)
//        var start = System.currentTimeMillis()
        while (needRun.get() && audioRecord.read(byteBuffer, byteBuffer.capacity()) > 0) {
//            Timber.i("minBuffer = ${minBufferSize}，给一帧音频所需要的时间：${System.currentTimeMillis() - start}")
//            start = System.currentTimeMillis()
            pcmProcessThreads.forEach { pcmProcessThread ->
                pcmProcessThread.pcmByteBufferPool.borrowObject()?.let { pcmByteBuffer -> // 从对象池借一个ByteBuffer
                    byteBuffer.rewind()
                    pcmByteBuffer.put(byteBuffer)
                    pcmByteBuffer.flip()
                    pcmProcessThread.addPcmToQueue(pcmByteBuffer) // 把pcm数据放到列队中
                }
            }
//            Timber.i("拷贝数据并放到队列所花时间：${System.currentTimeMillis() - start}")
//            start = System.currentTimeMillis()
        }
        needRun.set(false)
        audioRecord.stop()
        audioRecord.release()
        pcmProcessThreads.forEach(PCMProcessThread::close)
        Timber.i("录音结束")
    }

    fun stopRecord() {
        needRun.set(false)
    }

}